package cn.org.xiaoweiba.graduationdesign.bookmall.aspect;

import cn.org.xiaoweiba.graduationdesign.bookmall.annotation.string.StringNotNullAnnotation;
import cn.org.xiaoweiba.graduationdesign.bookmall.annotation.string.StringNotNullObjectAnnotation;
import cn.org.xiaoweiba.graduationdesign.bookmall.annotation.string.StringNotNullParameterAnnotation;
import cn.org.xiaoweiba.graduationdesign.bookmall.constant.ResponseResultMessageConstant;
import cn.org.xiaoweiba.graduationdesign.bookmall.dto.result.ClientErrorResponseResult;
import cn.org.xiaoweiba.graduationdesign.bookmall.dto.result.ServerErrorResponseResult;
import cn.org.xiaoweiba.graduationdesign.bookmall.utils.AspectUtil;
import cn.org.xiaoweiba.graduationdesign.bookmall.utils.ReflectUtil;
import cn.org.xiaoweiba.graduationdesign.bookmall.utils.StringUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * 判断切点方法中被 StringNotNullObjectAnnotation 或 StringNotNullParameterAnnotation
 * 标注的字符串类型的参数是否都不为空
 */
@Aspect
@Order(1)
@Component
public class StringNotNullAspect {

    /**
     * StringNotNullAspect 的切点为被注解 StringNotNullAnnotation 标注的位置
     */
    @Pointcut("@annotation(cn.org.xiaoweiba.graduationdesign.bookmall.annotation.string.StringNotNullAnnotation)")
    private void pointCut() {
    }

    /**
     * 判断切点方法中被 StringNotNullObjectAnnotation 或
     * StringNotNullParameterAnnotation 标注的字符串类型
     * 的参数是否为空
     *
     * @param proceedingJoinPoint 切点
     * @return 响应结果对象
     */
    @Around("pointCut()")
    public Object judgeStringIsNotNullAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        // 对每个参数进行判断，字符串类型是否为空
        Object[] results = AspectUtil.doParamHandleBeforeAdvice(
                proceedingJoinPoint,
                StringNotNullObjectAnnotation.class,
                (Object arg) -> {
                    // 判断对象形式参数中的字符串类型字段是否为空
                    // 存在为空 return false，否则 return true
                    return !judgeObjAllStrFieldIsNull(arg);
                },
                StringNotNullParameterAnnotation.class,
                (Object arg) -> {
                    // 当前字符串参数为空 return false，否则 return true
                    if (StringUtil.isNull((String) arg)) return false;
                    return true;
                }
        );
        // 如果要求非空的参数中，存在空，返回错误响应结果对象
        if (Arrays.stream(results).anyMatch((result) -> (Boolean) result == false)) {
            return ClientErrorResponseResult.errorResult(ResponseResultMessageConstant.PARAM_IS_NULL);
        }
        try {
            // 执行切点方法并返回切点方法的执行结果
            return proceedingJoinPoint.proceed();
        } catch (Throwable e) {
            // 响应服务器异常
            return ServerErrorResponseResult.errorResult(ResponseResultMessageConstant.SERVER_ERROR);
        }
    }

    /**
     * 判断对象中的所有字符串类型的被 StringNotNullAnnotation
     * 标注的字段是否存在为空，只要其中一个为空就返回 true
     *
     * @param object 对象
     * @return true 存在空；false 都不为空
     */
    private Boolean judgeObjAllStrFieldIsNull(Object object) {
        try {
            ReflectUtil.doObjectAllFieldHandleByAnnotation(
                    object,
                    (Object obj, Field field, Annotation[] annotations) -> {
                        // 当前字段没有被 StringNotNullAnnotation 标注直接判断下一个字段
                        if (!ReflectUtil.judgeContainAnnotation(annotations, StringNotNullAnnotation.class)) {
                            return;
                        }
                        // 当前字段被 StringNotNullAnnotation 标注，需要进行判断
                        // 获取当前字段的值
                        String fieldValue = null;
                        try {
                            fieldValue = (String) ReflectUtil.getFieldValue(obj, field);
                        } catch (IllegalAccessException ignored) {

                        }
                        // 当存在字符串为空时，抛出错误
                        if (StringUtil.isNull(fieldValue)) {
                            throw new RuntimeException();
                        }
                    }
            );
        } catch (Exception e) {
            // 接收到因字符串为空而抛出的错误，对象中的所有字符串类型的被
            // StringNotNullAnnotation 标注的字段存在为空
            return true;
        }
        // 对象中的所有字符串类型的被 StringNotNullAnnotation 标注的字段不存在为空
        return false;
    }

}
